/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.diagram.classdiagram.helper;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.ElementImport;
import org.eclipse.uml2.uml.Extension;
import org.eclipse.uml2.uml.ExtensionEnd;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.PackageableElement;
import org.eclipse.uml2.uml.Profile;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Stereotype;
import org.eclipse.uml2.uml.UMLFactory;

import com.cea.papyrus.core.helper.GraphEdgeHelper;
import com.cea.papyrus.core.helper.IGraphEdgeHelper;
import com.cea.papyrus.core.helper.NodeHelper;
import com.cea.papyrus.core.utils.Debug;
import com.cea.papyrus.diagraminterchange2.di2.Diagram;
import com.cea.papyrus.diagraminterchange2.di2.GraphEdge;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge;

/**
 * Helper for an {@link Extension}.
 */
public class EdgeExtensionHelper extends GraphEdgeHelper implements IGraphEdgeHelper{
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean canConnect(Element source,Element target){
	
		// test to know if the createConnection can be created on the source
		if ((source != null)&& (source instanceof Stereotype) && (target == null)) {
			return true;
		}
		
			// Source and target exist
		if ((source == null) || (target == null)) {
			return false;
		}
	
		// Target is an element import
		//if (!(target instanceof ElementImport)){
		//	return false;
		//}
		//target=((ElementImport)target).getImportedElement();

		// Testing node types (Stereotype and Metaclass) 
		if (!((source instanceof Stereotype) && (target instanceof ElementImport))) {
			return false;
		}
		
		if( !(((ElementImport)target).getImportedElement() instanceof Class)){
			return false;
		}
		// eltTarget should be stereotyped Metaclass
		com.cea.papyrus.umlutils.Element eltTargetUtils = new com.cea.papyrus.umlutils.Element(((ElementImport)target).getImportedElement());
		if (! eltTargetUtils.hasStereotype("Metaclass")) {
			return false;
		}

		// Everything is correct : canExecute return true
		return true;
	}

	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean canCreateGraphElement(GraphElement source){
		Element eltSource = null;
		
		// Source has a semantic model
		if (source == null){
			return false;
		}
		
		if ((source instanceof Diagram)  ){
			if (((Uml1SemanticModelBridge)((Diagram)source).getOwner()).getElement()!=null){
				eltSource=((Uml1SemanticModelBridge)((Diagram)source).getOwner()).getElement();
				if (eltSource instanceof Profile){return true;}
			}
		}
		
		if(source.getSemanticModel() == null) {
			return false;
		}
		eltSource = ((Uml1SemanticModelBridge) source.getSemanticModel()).getElement();
		
		if ((eltSource != null) && (eltSource instanceof Profile)) {
			return true;
		}
		
		return false;
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public GraphElement createGraphElement(Element umlChild, GraphElement parent, Point location, Dimension size) {
		
		GraphElement ge=super.createGraphElement(umlChild, null, location, size);
		NodeHelper nf=new NodeHelper();
//		name of extension
		GraphElement graphNode=nf.createGraphElement(null,ge,new Point(0, 10),null);
		graphNode.setFontSize(9);
		graphNode.setIsVisible(false);
		// required label of the extension
		graphNode=nf.createGraphElement(null,ge,new Point(0, 10),null);
		graphNode.setFontSize(9);
		graphNode.setIsVisible(false);
		
		//the parent is connected in last, because an eventis triggered.
		if( parent!=null){
			parent.getContained().add(ge);
		}
		
		return ge;			
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public ArrayList createGraphEdge(Element umlElement, Diagram diagram){
		Debug.debug(this,"createGraphEdge", 10);
		GraphEdge ge = (GraphEdge)this.createGraphElement(umlElement,null,null,null);
		//look for UML connected UML element
		if (!(umlElement instanceof Extension)){
			return new ArrayList();
		}
		
		Extension de=(Extension) umlElement;
		
		Element umlsource   = null;
		Element umlsupplier = null;
		
		// Affect source and supplier
		if (de.getEndTypes().get(0) instanceof Stereotype) {
			umlsource   = (Element) de.getEndTypes().get(0);
			umlsupplier = (Element) de.getEndTypes().get(1);
		} else {
			umlsource   = (Element) de.getEndTypes().get(1);
			umlsupplier	= (Element) de.getEndTypes().get(0);
		}
				
		super.endCreateGraphElement(umlsource, umlsupplier, ge, diagram);
		return new ArrayList();
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public  org.eclipse.uml2.uml.Element createUMLElement(String name, org.eclipse.uml2.uml.Element umlParent){
		Debug.debug(this,"create extension", channel); //$NON-NLS-1$
		Extension as= UMLFactory.eINSTANCE.createExtension();
		as.setName(name);
		((Package)umlParent).getPackagedElements().add(as);
		return as;		
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean canCreateUMLElement(Element umlParent) {
		if(umlParent instanceof Package) {
			return true;
		}
		return false;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean addUMLElement(Element element, Element umlParent) {
		if(umlParent instanceof Package) {
			return ((Package)umlParent).getPackagedElements().add((PackageableElement)element);
		}
		return false;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean removeUMLElement(Element element, Element umlParent) {
		if(umlParent instanceof Package) {
			return ((Package)umlParent).getPackagedElements().remove(element);
		}
		return false;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean connect(Element source, Element target, Element link) {
		Debug.debug(this,"   Detect Extension link", channel);

		Property property = (Property)source;
		ExtensionEnd extEnd = (ExtensionEnd)target;
		Extension extension=(Extension)link;
		// should change the name to Extension_XXY where XXY is the 
		extension.setName(extEnd.getName().replaceFirst("e", "E"));
	
		List<Property> memberEnds = extension.getMemberEnds();
		
		if((memberEnds.indexOf(extEnd) >=0)) {
			extension.getMemberEnds().move(0, extEnd);
		} else {
			extension.getMemberEnds().add(0, extEnd);
		}
	
		if((memberEnds.indexOf(property) >=0)) {
			extension.getMemberEnds().move(1, property);
		} else {
			extension.getMemberEnds().add(1, property);
		}
		return true;
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean deconnect(Element source, Element target, Element link) {
		Property property = (Property)source;
		ExtensionEnd extEnd = (ExtensionEnd)target;
		
		property.setAssociation(null);
		extEnd.setAssociation(null);
		return true;
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public String getBaseString() {
		return "Extension"; //$NON-NLS-1$
	}
}
